// locutor
// (c) 2008-2009, Normen Müller, normen.mueller@gmail.com  
// $Id: G.scala 2482 2009-10-07 16:55:33Z nmueller $
package locutor.model

import java.io.File
import java.net.URL

import scalaxx.xpath.{Expr => XPath}

import scaup.data._

/** 
 * @author <a href="mailto:normen.mueller@googlemail.com">Normen M&#xFC;ller</a>
 * @version 0.0.2 */
private [model] class G(val name: String, val document: File, val revision: Int) extends MultiGraph
  with MultiGraph#NodeLabels[Map[String, String]]
  with MultiGraph#EdgeLabels[Map[String, String]]
  with MultiGraph#Directions
{     
  //@todo nodes should be mapped by (URL, XPath)
  private val nodes = collection.mutable.HashMap.empty[String, V]
  private var edges: List[E] = Nil
    
  type A = Map[String, String]
    
  type V = Infom
  
  private [G] case class Infom(id: String, t: String, url: URL, xpath: XPath, label: A) extends Node { self: V =>
    def ->(v: V): E = (this connectTo v)("Infom", Map())
    def connectTo(v: V)(t: String, attributes: A): E = ℯ(this, t, v)(attributes)
    
    def inDegree: Int = incoming.size
    def incoming: Set[E] = E filter {case Dependency(_, _, target, _) if target == this => true case _ => false}
      
    def outDegree: Int = outgoing.size
    def outgoing: Set[E] = E filter {case Dependency(source, _, _, _) if source == this => true case _ => false}
        
    def degree: Int = inDegree + outDegree
  }
  
  def η(id: String, t: String, url: URL, xpath: XPath, attributes: A): V = {
    nodes += {(id, Infom(id, t, url, xpath, attributes))}
    nodes(id)  
  }
  
  def apply (id: String): Option[V] = nodes get id
  
  type E = Dependency
  
  private [G] case class Dependency(override val source: V, t: String, override val target: V, label: A)
    extends Edge(source, target)
  {
    
  }
  
  def ℯ(src: V, t: String, tgt: V)(attributes: A): E = {
    val d = Dependency(src, t, tgt, attributes)
    edges ::= d
    d
  }
  
  def V = Set.empty[V] ++ nodes.values
  
  def E = Set.empty[E] ++ edges
}
